#include "tms_db.hpp"

int BaseDBAccessior::load_CSV()
{
    std::string line;
    std::vector<std::string> headers;
    std::vector<std::string> row;
    std::stringstream ss;
    std::string cell;
    int row_index = 0;

    std::ifstream file(this->file_name);

    if (!file.is_open())
    {
        throw std::runtime_error(tms::OPEN_FILE_ERR);
    }

    for (row_index = 0; std::getline(file, line); row_index++)
    {
        // 处理文件行尾，不同平台或者不同 CSV 编辑器生成的行尾可能有所区别
        for (; !line.empty() && (line.back() == '\r' || line.back() == '\n'); line.pop_back())
            ;

        ss = static_cast<std::stringstream>(line);
        row.clear();

        for (; std::getline(ss, cell, ','); row.push_back(cell))
            ;

        // 取出第一行作为表头，余下作为内容，压入数组
        if (row_index == 0)
        {
            headers = row;
            this->data.push_back(row);
        }
        else
        {
            if (row.size() != headers.size())
            {
                file.close();
                throw std::invalid_argument(tms::CSV_PRASE_ERR);
            }
            this->data.push_back(row);
        }
    }

    file.close();
    return row_index;
};

int BaseDBAccessior::write_CSV() const
{
    std::ofstream file(this->file_name);

    if (!file.is_open())
    {
        throw std::runtime_error(tms::OPEN_FILE_ERR);
    }

    size_t i = 0;
    for (i = 0; i < this->data.size(); i++)
    {
        for (size_t j = 0; j < this->data[i].size(); j++)
        {
            file << this->data[i][j] << ((j == (this->data[i].size() - 1)) ? ("") : (","));
        }

        file << std::endl;
    }

    file.close();
    return static_cast<int>(i);
};

BaseDBAccessior::BaseDBAccessior(const std::string &f) : file_name(f)
{
    int row_cnt = this->load_CSV();
#ifdef _TMS_DB_TEST
    std::cout << "Load CSV data base file: " << file_name;
    std::cout << " with row count: " << row_cnt << std::endl;
#endif
};

field BaseDBAccessior::select(const std::string &tar_row, const std::string &tar_var) const
{
    std::vector<std::string> headers = this->data[0];
    std::vector<std::vector<std::string>> result;
    int tar_col_i = -1;

    // 查找目标列的索引
    for (size_t i = 0; i < headers.size(); i++)
    {
        if (headers[i] == tar_row)
        {
            tar_col_i = static_cast<int>(i);
            break;
        }
    }

    if (tar_col_i == -1)
    {
        throw std::invalid_argument(tms::ROW_NOT_FOUND + tar_row);
    }

    // 遍历数据，查找符合要求的行
    for (size_t i = 1; i < data.size(); i++)
    {
        if (("*" == tar_var) || (data[i][tar_col_i] == tar_var))
        {
            result.push_back(data[i]);
        }
    }

    return result;
}

int BaseDBAccessior::update(const field &f)
{
    // 主键默认是第一列值
    // 此方法先分析传入数据的行，然后查询已经存在的主键，然后更新这一行
    int success_write_cnt = 0;

    // 检查数据合规性
    if (!(f.size()))
    {
        return 0;
    }
    if (!(f[0].size() == this->data[0].size()))
    {
        throw std::runtime_error(tms::DATA_SHAPE_ERR);
    }

    for (size_t i = 0; i < f.size(); i++)
    {
        for (size_t j = 0; j < this->data.size(); j++)
        {
            if (f[i][0] == this->data[j][0])
            {
                this->data[j] = f[i];
                success_write_cnt++;
            }
        }
    }

    return success_write_cnt;
};

int BaseDBAccessior::insert(const field &f)
{
    // 此方法先分析传入数据的行，然后查询已经存在的主键，如果逐渐存在就跳过，不存在就注册新行
    int success_write_cnt = 0;
    int is_deplict = 0;

    // 检查数据合规性
    if (!(f.size()))
    {
        return 0;
    }
    if (!(f[0].size() == this->data[0].size()))
    {
        throw std::runtime_error(tms::DATA_SHAPE_ERR);
    }

    for (size_t i = 0; i < f.size(); i++)
    {
        for (size_t j = 0; j < this->data.size(); j++)
        {
            if (f[i][0] == this->data[j][0])
            {
                // 重复主键，直接重开
                is_deplict = 1;
                break;
            }
        }

        if (!is_deplict)
        {
            this->data.push_back(f[i]);
            success_write_cnt++;
        }
    }

    return success_write_cnt;
};

int BaseDBAccessior::del(const std::string &tar_row, const std::string &selector)
{
    std::vector<std::string> headers = this->data[0];
    int tar_col_i = -1, del_row_cnt = 0;

    // 查找目标列的索引
    for (size_t i = 0; i < headers.size(); i++)
    {
        if (headers[i] == tar_row)
        {
            tar_col_i = static_cast<int>(i);
            break;
        }
    }

    if (tar_col_i == -1)
    {
        throw std::invalid_argument(tms::ROW_NOT_FOUND + tar_row);
    }

    // 遍历数据，查找符合要求的行
    for (size_t i = 1; i < data.size(); i++)
    {
        if (("*" == selector) || (data[i][tar_col_i] == selector))
        {
            this->data.erase(this->data.begin() + i);
            del_row_cnt++;
        }
    }

    return del_row_cnt;
}

int BaseDBAccessior::commit() const
{
    int row_cnt = this->write_CSV();
#ifdef _TMS_DB_TEST
    std::cout << "Write CSV data base file: " << this->file_name;
    std::cout << " with row count: " << row_cnt << std::endl;
#endif
    return row_cnt;
};

std::string BaseDBAccessior::print2str(const field &f)
{
    std::stringstream ss;

    for (size_t i = 0; i < f.size(); i++)
    {
        for (size_t j = 0; j < f[i].size(); j++)
        {
            ss << f[i][j] << ((j == (f[i].size() - 1)) ? ("") : (", "));
        }
        ss << std::endl;
    }

    return ss.str();
}

TimeTableItem::TimeTableItem(const std::vector<std::string> &row)
    : time_table_id(row[0]),
      time_launch(row[1]),
      spot_launch(row[2]),
      spot_arrive(row[3]),
      duration(row[4]),
      ticket_price(std::stod(row[5])),
      capacity(std::stoi(row[6])),
      ticket_sold_cnt(std::stoi(row[7])),
      is_canceled(static_cast<int>(row[8] == "1")) {};

TimeTableItem::TimeTableItem(
    const std::string &time_table_id,
    const std::string &time_launch,
    const std::string &spot_launch,
    const std::string &spot_arrive,
    const std::string &duration,
    double ticket_price,
    int capacity,
    int ticket_sold_cnt,
    int is_canceled)
    : time_table_id(time_table_id),
      time_launch(time_launch),
      spot_launch(spot_launch),
      spot_arrive(spot_arrive),
      duration(duration),
      ticket_price(ticket_price),
      capacity(capacity),
      ticket_sold_cnt(ticket_sold_cnt),
      is_canceled(is_canceled) {};

SaleItem::SaleItem(const std::vector<std::string> &row)
    : ticket_id(row[0]),
      time_id(row[1]),
      buyer_id(row[2]) {};

SaleItem::SaleItem(const std::string &ticket_id,
                   const std::string &time_id,
                   const std::string &buyer_id)
    : ticket_id(ticket_id),
      time_id(time_id),
      buyer_id(buyer_id) {};

UserItem::UserItem(const std::vector<std::string> &row)
    : user_id(row[0]),
      name(row[1]),
      passwd(row[2]),
      wallet(std::stod(row[3])) {};

UserItem::UserItem(const std::string &user_id,
                   const std::string &name,
                   const std::string &passwd,
                   double wallet)
    : user_id(user_id),
      name(name),
      passwd(passwd),
      wallet(wallet) {};

TmsDataBackend::TmsDataBackend(const std::string &time_table_file,
                               const std::string &user_file,
                               const std::string &sales_file)
    : time_table_db(new BaseDBAccessior(time_table_file)),
      user_db(new BaseDBAccessior(user_file)),
      sales_db(new BaseDBAccessior(sales_file)) {};

TmsDataBackend::~TmsDataBackend()
{
    delete time_table_db;
    delete user_db;
    delete sales_db;
}

/* 数据库内部方法 */
std::string TmsDataBackend::get_next_ticket_id() const
{
    const int START_ID = 1;

    field res = sales_db->select("ticket_id", "*");
    if (res.empty())
    {
        return std::to_string(static_cast<long long>(START_ID));
    }

    int max_id = START_ID;
    for (size_t i = 0; i < res.size(); i++)
    {
        int id = std::stoi(res[i][0]);
        if (id > max_id)
        {
            max_id = id;
        }
    }

    return std::to_string(static_cast<long long>(max_id + 1));
}

std::string TmsDataBackend::get_next_time_table_id() const
{
    const int START_ID = 1;

    field res = time_table_db->select("time_table_id", "*");
    if (res.empty())
    {
        return std::to_string(static_cast<long long>(START_ID));
    }

    int max_id = 2;
    for (size_t i = 0; i < res.size(); i++)
    {
        int id = std::stoi(res[i][0]);
        if (id > max_id)
        {
            max_id = id;
        }
    }

    return std::to_string(static_cast<long long>(max_id + 1));
}

inline int TmsDataBackend::time_to_minutes(const std::string &time_str)
{
    std::istringstream iss(time_str);
    int hours, minutes;
    char colon;
    iss >> hours >> colon >> minutes;
    return hours * 60 + minutes;
}

inline bool TmsDataBackend::compare_by_launch_time(const TimeTableItem &a, const TimeTableItem &b)
{
    return time_to_minutes(a.time_launch) < time_to_minutes(b.time_launch);
}

/* 数据格式化工具 */
std::string TmsDataBackend::time_table2string(const std::vector<TimeTableItem> &items, const int col_w, const int coloring, const int header, const int use_csv)
{
    std::stringstream ss_cache;

    if (header)
    {
        if (use_csv)
        {
            ss_cache << tms::TAB_TRAIN_ID
                     << "," << tms::TAB_LAUNCH_SPOT
                     << "," << tms::TAB_LAUNCH_TIME
                     << "," << tms::TAB_ARRIVE_SPOT
                     << "," << tms::TAB_DURATION
                     << "," << tms::TAB_PRICE
                     << "," << tms::TAB_CAPACITY
                     << "," << tms::TAB_SOLD_TICKETS
                     << "," << tms::TAB_CANCEL << std::endl;
        }
        else
        {
            ss_cache << std::left
                     << std::setw(col_w) << tms::TAB_TRAIN_ID
                     << std::setw(col_w) << tms::TAB_LAUNCH_SPOT
                     << std::setw(col_w) << tms::TAB_LAUNCH_TIME
                     << std::setw(col_w) << tms::TAB_ARRIVE_SPOT
                     << std::setw(col_w) << tms::TAB_DURATION
                     << std::setw(col_w) << tms::TAB_PRICE
                     << std::setw(col_w) << tms::TAB_CAPACITY
                     << std::setw(col_w) << tms::TAB_SOLD_TICKETS
                     << tms::TAB_CANCEL << std::endl;
        }
    }

    for (size_t i = 0; i < items.size(); i++)
    {
        std::string time_bg_color = coloring ? get_time_status_bg_color(items[i].time_launch) : tms::RESET_BG;

        if (use_csv)
        {
            ss_cache << items[i].time_table_id
                     << "," << items[i].time_launch
                     << "," << items[i].spot_launch
                     << "," << items[i].spot_arrive
                     << "," << items[i].duration
                     << "," << items[i].ticket_price
                     << "," << items[i].capacity
                     << "," << items[i].ticket_sold_cnt
                     << "," << items[i].is_canceled << std::endl;
        }
        else
        {
            ss_cache << std::left
                     << std::setw(col_w) << items[i].time_table_id
                     << time_bg_color
                     << std::setw(col_w) << items[i].time_launch
                     << tms::RESET_BG
                     << std::setw(col_w) << items[i].spot_launch
                     << std::setw(col_w) << items[i].spot_arrive
                     << std::setw(col_w) << items[i].duration
                     << std::setw(col_w) << items[i].ticket_price
                     << std::setw(col_w) << items[i].capacity
                     << std::setw(col_w) << items[i].ticket_sold_cnt
                     << (coloring ? (items[i].is_canceled ? tms::RED_BG : tms::GREEN_BG) : tms::RESET_BG)
                     << (items[i].is_canceled ? "Yes" : "No")
                     << tms::RESET_BG << std::endl;
        }
    }

    return ss_cache.str();
}

std::string TmsDataBackend::sales2string(const std::vector<SaleItem> &items, const int col_w)
{
    std::stringstream ss_cache;

    ss_cache << std::left << std::setw(col_w) << tms::TAB_TICKET_ID
             << std::setw(col_w) << tms::TAB_TIME_ID
             << std::setw(col_w) << tms::TAB_BUYER_ID << std::endl;

    for (size_t i = 0; i < items.size(); i++)
    {
        ss_cache << std::left << std::setw(col_w) << items[i].ticket_id
                 << std::setw(col_w) << items[i].time_id
                 << std::setw(col_w) << items[i].buyer_id << std::endl;
    }

    return ss_cache.str();
}

std::string TmsDataBackend::user2string(const std::vector<UserItem> &items, const int col_w)
{
    std::stringstream ss_cache;

    ss_cache << std::left << std::setw(col_w) << tms::TAB_USER_ID
             << std::setw(col_w) << tms::TAB_USER_NAME
             << std::setw(col_w) << tms::TAB_USER_PASSWD
             << std::setw(col_w) << tms::TAB_WALLET << std::endl;

    for (size_t i = 0; i < items.size(); i++)
    {
        ss_cache << std::left << std::setw(col_w) << items[i].user_id
                 << std::setw(col_w) << items[i].name
                 << std::setw(col_w) << items[i].passwd
                 << std::setw(col_w) << items[i].wallet << std::endl;
    }

    return ss_cache.str();
}

std::string TmsDataBackend::get_current_time()
{
    std::time_t now = std::time(nullptr);
    std::tm *local_time = std::localtime(&now);
    if (!local_time)
    {
        return "";
    }

    std::ostringstream oss;
    oss << std::put_time(local_time, "%H:%M");
    return oss.str();
}

std::string TmsDataBackend::get_time_status_bg_color(const std::string &time_launch)
{
    std::string current_time = get_current_time();
    if (current_time.empty())
    {
        return tms::RESET_BG;
    }

    int current_time_in_minutes = time_to_minutes(current_time);
    int launch_time_in_minutes = time_to_minutes(time_launch);

    if (launch_time_in_minutes < current_time_in_minutes)
    {
        return tms::RED_BG;
    }
    else if (launch_time_in_minutes - current_time_in_minutes <= tms::TICKETS_CHECK_THER)
    {
        return tms::YELLOW_BG;
    }
    else if (launch_time_in_minutes - current_time_in_minutes <= tms::BOARDING_THER)
    {
        return tms::BLUE_BG;
    }
    else
    {
        return tms::GREEN_BG;
    }
}

std::vector<TimeTableItem> TmsDataBackend::list_all_trains() const
{
    field res = time_table_db->select("time_table_id", "*");
    std::vector<TimeTableItem> items;

    for (size_t i = 0; i < res.size(); i++)
    {
        // 构造并插入对象
        items.emplace_back(res[i]);
    }

    std::sort(items.begin(), items.end(), compare_by_launch_time);

    return items;
}

std::vector<TimeTableItem> TmsDataBackend::query_train_by_id(const std::string &time_table_id) const
{
    field res = time_table_db->select("time_table_id", time_table_id);
    std::vector<TimeTableItem> items;

    for (size_t i = 0; i < res.size(); i++)
    {
        items.emplace_back(res[i]);
    }

    // 按发车时间排序
    std::sort(items.begin(), items.end(), compare_by_launch_time);

    return items;
}

std::vector<TimeTableItem> TmsDataBackend::query_train_by_arrive_spot(const std::string &spot_arrive) const
{
    field res = time_table_db->select("spot_arrive", spot_arrive);
    std::vector<TimeTableItem> items;

    for (size_t i = 0; i < res.size(); i++)
    {
        items.emplace_back(res[i]);
    }

    // 按发车时间排序
    std::sort(items.begin(), items.end(), compare_by_launch_time);

    return items;
}

int TmsDataBackend::add_train(const TimeTableItem &new_train)
{
    // add_train 不再检查 ID 而是直接分配新 ID
    // 创建新的车次数据行
#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_train_row = {
        get_next_time_table_id(),
        new_train.time_launch,
        new_train.spot_launch,
        new_train.spot_arrive,
        new_train.duration,
        std::to_string(static_cast<long long>(new_train.ticket_price)),
        std::to_string(static_cast<long long>(new_train.capacity)),
        std::to_string(static_cast<long long>(new_train.ticket_sold_cnt)),
        new_train.is_canceled ? "1" : "0"};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_train_row;
    new_train_row.push_back(get_next_time_table_id());
    new_train_row.push_back(new_train.time_launch);
    new_train_row.push_back(new_train.spot_launch);
    new_train_row.push_back(new_train.spot_arrive);
    new_train_row.push_back(new_train.duration);
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.ticket_price)));
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.capacity)));
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.ticket_sold_cnt)));
    new_train_row.push_back(new_train.is_canceled ? "1" : "0");
#endif

    field new_trains;
    new_trains.push_back(new_train_row);

    return time_table_db->insert(new_trains);
}

int TmsDataBackend::modify_train(const TimeTableItem &new_train)
{
    // 修改时间表
#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_train_row = {
        new_train.time_table_id,
        new_train.time_launch,
        new_train.spot_launch,
        new_train.spot_arrive,
        new_train.duration,
        std::to_string(static_cast<long long>(new_train.ticket_price)),
        std::to_string(static_cast<long long>(new_train.capacity)),
        std::to_string(static_cast<long long>(new_train.ticket_sold_cnt)),
        new_train.is_canceled ? "1" : "0"};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_train_row;
    new_train_row.push_back(new_train.time_table_id);
    new_train_row.push_back(new_train.time_launch);
    new_train_row.push_back(new_train.spot_launch);
    new_train_row.push_back(new_train.spot_arrive);
    new_train_row.push_back(new_train.duration);
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.ticket_price)));
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.capacity)));
    new_train_row.push_back(std::to_string(static_cast<long long>(new_train.ticket_sold_cnt)));
    new_train_row.push_back(new_train.is_canceled ? "1" : "0");
#endif

    field new_trains;
    new_trains.push_back(new_train_row);

    return time_table_db->update(new_trains);
}

int TmsDataBackend::cancel_train(const std::string &train_id)
{
    field res = time_table_db->select("time_table_id", train_id);
    if (res.empty())
    {
        return 0;
    }

    for (size_t i = 0; i < res.size(); i++)
    {
        // 将 is_canceled 更改为 1
        res[i][8] = "1";
    }

    return time_table_db->update(res);
}

std::vector<SaleItem> TmsDataBackend::get_sales_by_user(const std::string &user_id) const
{
    field res = sales_db->select("buyer_id", user_id);
    std::vector<SaleItem> items;

    for (size_t i = 0; i < res.size(); i++)
    {
        items.emplace_back(res[i]);
    }

    return items;
}

int TmsDataBackend::register_user(const UserItem &new_user)
{
    // 检查用户ID是否已存在
    field res = user_db->select("user_id", new_user.user_id);
    if (!res.empty())
    {
        throw std::runtime_error(tms::USER_ID_EXIST_ERR);
    }

// 创建新的用户数据行
#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_user_row = {
        new_user.user_id,
        new_user.name,
        new_user.passwd,
        std::to_string(static_cast<long long>(new_user.wallet))};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_user_row;
    new_user_row.push_back(new_user.user_id);
    new_user_row.push_back(new_user.name);
    new_user_row.push_back(new_user.passwd);
    new_user_row.push_back(std::to_string(static_cast<long long>(new_user.wallet)));
#endif

    field new_users;
    new_users.push_back(new_user_row);

    return user_db->insert(new_users);
}

int TmsDataBackend::verify_user(const std::string &user_id, const std::string &passwd) const
{
    field res = user_db->select("user_id", user_id);
    if (res.empty())
    {
        throw std::runtime_error(tms::USER_NOT_FOUND_ERR);
    }

    if (res[0][2] != passwd)
    {
        throw std::runtime_error(tms::PASSWD_INCORRECT);
    }

    return 1;
}

int TmsDataBackend::modify_user(const UserItem &updated_user)
{
    // 检查用户ID是否已存在
    field res = user_db->select("user_id", updated_user.user_id);
    if (res.empty())
    {
        throw std::runtime_error(tms::USER_NOT_FOUND_ERR);
    }

// 只更新姓名和密码
// 行为上调整到，保持原钱包余额，忽略任何更改
#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> updated_row = {
        updated_user.user_id,
        updated_user.name,
        updated_user.passwd,
        res[0][3]};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> updated_row;
    updated_row.push_back(updated_user.user_id);
    updated_row.push_back(updated_user.name);
    updated_row.push_back(updated_user.passwd);
    updated_row.push_back(res[0][3]);
#endif

    field updated_users;
    updated_users.push_back(updated_row);

    return user_db->update(updated_users);
}

UserItem TmsDataBackend::find_user_by_id(const std::string &user_id) const
{
    field res = user_db->select("user_id", user_id);
    if (res.empty())
    {
        throw std::runtime_error(tms::USER_NOT_FOUND_ERR);
    }

    return UserItem(res[0]);
}

std::vector<UserItem> TmsDataBackend::query_user_by_id(const std::string &selector) const
{
    field res = user_db->select("user_id", selector);
    std::vector<UserItem> users;

    for (size_t i = 0; i < res.size(); i++)
    {
        users.emplace_back(res[i]);
    }

    return users;
}

std::vector<UserItem> TmsDataBackend::list_all_users() const
{
    field res = user_db->select("user_id", "*");
    std::vector<UserItem> users;

    for (size_t i = 0; i < res.size(); i++)
    {
        users.emplace_back(res[i]);
    }

    return users;
}

int TmsDataBackend::charge_user_wallet(const std::string &user_id, double charge)
{
    field res = user_db->select("user_id", user_id);
    if (res.empty())
    {
        return 0;
    }

    for (size_t i = 0; i < res.size(); i++)
    {
        res[i][3] = std::to_string(static_cast<long long>(charge + std::stod(res[i][3])));
    }

    return user_db->update(res);
}

int TmsDataBackend::pay_user_wallet(const std::string &user_id, double payment)
{
    field res = user_db->select("user_id", user_id);
    if (res.empty())
    {
        return -1;
    }

    double new_wallet = std::stod(res[0][3]) - payment;
    if (new_wallet > 0)
    {
        res[0][3] = std::to_string(static_cast<long long>(new_wallet));
        return user_db->update(res);
    }
    else
    {
        return -1;
    }

    return -1;
}

int TmsDataBackend::purchase_ticket(const std::string &user_id, const std::string &train_id)
{
    // 购票逻辑代码
    // 购票逻辑比较复杂，首先根据用户 ID 查找用户，然后查找车次，同时确定用户没有买过这个车次的票，还有余量车次
    // 然后，方法会先更新用户的钱包数据，确定钱包可以购票，然后写入售票数据库更改，最后减少售票

    // 查询用户
    UserItem user = find_user_by_id(user_id);

    // 查询车次
    std::vector<TimeTableItem> trains = query_train_by_id(train_id);
    if (trains.empty())
    {
        throw std::runtime_error(tms::NO_TICKET_FOUND);
    }
    TimeTableItem train = trains[0];

    // 检查车次是否已取消
    if (train.is_canceled)
    {
        throw std::runtime_error(tms::TRAIN_CANCEL_ERR);
    }

    // 检查是否发车前10分钟内或发车后
    int current_time_in_minutes = time_to_minutes(get_current_time());
    int launch_time_in_minutes = time_to_minutes(train.time_launch);

    if (launch_time_in_minutes < current_time_in_minutes ||
        (launch_time_in_minutes - current_time_in_minutes) < tms::BOARDING_THER)
    {
        throw std::runtime_error(tms::TICKETS_TIME_OUTTIME_ERR);
    }

    // 检查用户是否已经购买过该车次的票
    field sales_res = sales_db->select("buyer_id", user_id);
    for (size_t i = 0; i < sales_res.size(); i++)
    {
        if (sales_res[i][1] == train_id)
        {
            throw std::runtime_error(tms::BUY_SAME_TICKET_ERR);
        }
    }

    int pay_res = pay_user_wallet(user_id, train.ticket_price);

    if (pay_res < 0)
    {
        throw std::runtime_error(tms::WALLET_RUN_OUT_ERR);
    }

    if (train.ticket_sold_cnt >= train.capacity)
    {
        throw std::runtime_error(tms::NO_SIT_TO_SALE);
    }

// 写入售票记录
#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_sale = {
        get_next_ticket_id(),
        train_id,
        user_id};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_sale;
    new_sale.push_back(get_next_ticket_id());
    new_sale.push_back(train_id);
    new_sale.push_back(user_id);
#endif

    field new_sales;
    new_sales.push_back(new_sale);

    train.ticket_sold_cnt++;

#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_train_row = {
        train.time_table_id,
        train.time_launch,
        train.spot_launch,
        train.spot_arrive,
        train.duration,
        std::to_string(static_cast<long long>(train.ticket_price)),
        std::to_string(static_cast<long long>(train.capacity)),
        std::to_string(static_cast<long long>(train.ticket_sold_cnt)),
        train.is_canceled ? "1" : "0"};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_train_row;
    new_train_row.push_back(train.time_table_id);
    new_train_row.push_back(train.time_launch);
    new_train_row.push_back(train.spot_launch);
    new_train_row.push_back(train.spot_arrive);
    new_train_row.push_back(train.duration);
    new_train_row.push_back(std::to_string(static_cast<long long>(train.ticket_price)));
    new_train_row.push_back(std::to_string(static_cast<long long>(train.capacity)));
    new_train_row.push_back(std::to_string(static_cast<long long>(train.ticket_sold_cnt)));
    new_train_row.push_back(train.is_canceled ? "1" : "0");
#endif

    field new_trains;
    new_trains.push_back(new_train_row);

    return sales_db->insert(new_sales) + time_table_db->update(new_trains);
}

int TmsDataBackend::refund_ticket(const std::string &user_id, const std::string &ticket_id)
{
    // 退票流程也是比较复杂的
    // 方法首先检查是否存在购票记录，然后核对是否是本人的购票，然后再检查收费在开车前十分钟
    // 达到退票条件之后，方法会先归还时间表订票名额，删除购票记录，最后按照手续费退钱

    field tar_sales = sales_db->select("ticket_id", ticket_id);
    if (tar_sales.empty())
    {
        throw std::runtime_error(tms::NO_TICKET_FOUND);
    }
    std::vector<std::string> tar_sale = tar_sales[0];
    TimeTableItem train = query_train_by_id(tar_sale[1])[0];

    if (tar_sale[2] != user_id)
    {
        throw std::runtime_error(tms::NOT_THIS_USER_TICKET);
    }

    // 检查是否发车前10分钟内或发车后
    int current_time_in_minutes = time_to_minutes(get_current_time());
    int launch_time_in_minutes = time_to_minutes(train.time_launch);

    if (launch_time_in_minutes < current_time_in_minutes ||
        (launch_time_in_minutes - current_time_in_minutes) < tms::BOARDING_THER)
    {
        throw std::runtime_error(tms::TICKETS_TIME_OUTTIME_ERR);
    }

    charge_user_wallet(user_id, train.ticket_price);

    train.ticket_sold_cnt--;

#ifdef TMS_POSIX_PLATFORM
    std::vector<std::string> new_train_row = {
        train.time_table_id,
        train.time_launch,
        train.spot_launch,
        train.spot_arrive,
        train.duration,
        std::to_string(static_cast<long long>(train.ticket_price)),
        std::to_string(static_cast<long long>(train.capacity)),
        std::to_string(static_cast<long long>(train.ticket_sold_cnt)),
        train.is_canceled ? "1" : "0"};
#endif

#ifdef TMS_WIN32_PLATFORM
    std::vector<std::string> new_train_row;
    new_train_row.push_back(train.time_table_id);
    new_train_row.push_back(train.time_launch);
    new_train_row.push_back(train.spot_launch);
    new_train_row.push_back(train.spot_arrive);
    new_train_row.push_back(train.duration);
    new_train_row.push_back(std::to_string(static_cast<long long>(train.ticket_price)));
    new_train_row.push_back(std::to_string(static_cast<long long>(train.capacity)));
    new_train_row.push_back(std::to_string(static_cast<long long>(train.ticket_sold_cnt)));
    new_train_row.push_back(train.is_canceled ? "1" : "0");
#endif

    field new_trains;
    new_trains.push_back(new_train_row);

    return sales_db->del("ticket_id", ticket_id) + time_table_db->update(new_trains);
}

int TmsDataBackend::del_train(const std::string &train_id)
{
    return time_table_db->del("time_table_id", train_id);
}

int TmsDataBackend::del_user(const std::string &user_id)
{
    return user_db->del("user_id", user_id);
}

int TmsDataBackend::export_log_file(const std::string &file_name)
{
    std::ofstream f(file_name);

    if (!f.is_open())
    {
        return 0;
    }

    std::string content = time_table2string(list_all_trains(), 0, 0, 1, 1);

    f << content;

    f.close();

    return content.size();
}

int TmsDataBackend::commit_changes() const
{
    time_table_db->commit();
    user_db->commit();
    sales_db->commit();
    return 1;
}

/*
数据库测试逻辑
加载时间表数据库，查询条目并输出
*/
#ifdef _TMS_DB_TEST
// TODO 更新数据库测试流程，这个太复杂了

void print_time_table_items(const std::vector<TimeTableItem> &items)
{
    const int COL_WIDTH = 20;

    std::cout << TmsDataBackend::time_table2string(items, COL_WIDTH, 0, 0, 1);
}

void print_sale_items(const std::vector<SaleItem> &items)
{
    std::cout << TmsDataBackend::sales2string(items, 20);
}

void print_user_items(const std::vector<UserItem> &items)
{
    std::cout << TmsDataBackend::user2string(items, 20);
}

int main()
{
    try
    {
        // 初始化数据库
        TmsDataBackend tms_db("../db/time_table.csv", "../db/user.csv", "../db/sales.csv");

        // 测试列出所有车次
        auto all_trains = tms_db.list_all_trains();
        std::cout << "All Trains Count: " << all_trains.size() << std::endl;

        // 测试按站点查询车次 - 使用已有站点
        auto nanjing_trains = tms_db.query_train_by_arrive_spot("Nanjing South");
        std::cout << "Trains arrive Nanjing South Station Count: " << nanjing_trains.size() << std::endl;

        // 测试按车次号查询车次
        auto six_train = tms_db.query_train_by_id("6");
        std::cout << "Train number 6 Count: " << six_train.size() << std::endl;

        // 测试增加车次 - 使用已有站点
        TimeTableItem new_train(
            "1001", "09:00", "Nanjing South", "Yan City", "02h30m", 54.5, 300, 0, 0);
        int added = tms_db.add_train(new_train);
        std::cout << "Train added: " << added << std::endl;

        // 测试注销车次
        int canceled = tms_db.cancel_train("3");
        std::cout << "Train canceled: " << canceled << std::endl;

        // 测试获取用户销售记录
        auto sales = tms_db.get_sales_by_user("zhangsan");
        std::cout << "Sales for user 'zhangsan' Count: " << sales.size() << std::endl;

        // 测试列出所有用户
        auto users = tms_db.list_all_users();
        std::cout << "All Users Count: " << users.size() << std::endl;

        // 测试注册用户
        UserItem new_user("wangwu", "王五", "ww123456", 1500.0);
        try
        {
            int registered = tms_db.register_user(new_user);
            std::cout << "User registered: " << registered << std::endl;
        }
        catch (const std::runtime_error &e)
        {
            std::cerr << "Error registering user: " << e.what() << std::endl;
        }

        // 测试验证用户
        try
        {
            tms_db.verify_user("zhangsan", "zsnb");
            std::cout << "Verifying user 'zhangsan' with password 'zsnb': Success" << std::endl;
        }
        catch (const std::runtime_error &e)
        {
            std::cerr << "Verification failed: " << e.what() << std::endl;
        }

        // 测试更新用户钱包余额
        int updated = tms_db.charge_user_wallet("zhangsan", 1200.0);
        std::cout << "Wallet updated: " << updated << std::endl;

        // 测试修改用户信息
        UserItem user_r = tms_db.find_user_by_id("rice");
        user_r.name = "tri";
        user_r.passwd = "told";
        tms_db.modify_user(user_r);

        // 测试购买车票
        try
        {
            int purchased = tms_db.purchase_ticket("rice", "1");
            std::cout << "Ticket purchased: " << purchased << std::endl;
        }
        catch (const std::runtime_error &e)
        {
            std::cerr << "Error purchasing ticket: " << e.what() << std::endl;
        }

        // 测试退订车票
        try
        {
            int refunded = tms_db.refund_ticket("rice", "10002");
            std::cout << "Ticket refunded: " << refunded << std::endl;
        }
        catch (const std::runtime_error &e)
        {
            std::cerr << "Error refunding ticket: " << e.what() << std::endl;
        }

        // 测试删除用户
        tms_db.del_user("wangwu");

        // 测试删除车次
        tms_db.del_train("1001");

        // 测试导出日志
        tms_db.export_log_file("../db/f.log");

        // 提交更改
        // tms_db.commit_changes();
        // std::cout << "Changes committed." << std::endl;
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
#endif
